#include "mdi_common.h"
#include "mpi_lib.h"
#include "mpi.h"
#include "mpi_cmd.h"
#include "mpi_sys.h"
#include "mpi_vo.h"
#include "mpi_osd.h"
#include "mpi_venc.h"

#define OSD_AREA_TOTAL_NUM                 (OSD_PLANE_NUM * OSD_AREA_NUM)
#define OSD_CLUT_SIZE                      (1024)
#define OSD_CLUT_OFFSET                    (0)
#define OSD_YUV_OFFSET                     (OSD_AREA_TOTAL_NUM * OSD_CLUT_SIZE)
#define GET_DSP_CMD_CODE(cmd_code, stream) ((cmd_code) | (((stream) & 0x3) << 30))

typedef struct __OsdVoObj
{
    int fdhandle;
    /*framebufer enable flag*/
    int fbEn;
    sgks_dram_osd_s  *osdBufInfo;
} osdVoObj_s;

typedef enum __sgks_osd_voSrc
{
    SGKS_OSD_VO_SRC_MAPPED_IN    = 0,
    SGKS_OSD_VO_SRC_DIRECT_IN    = 1,
} sgks_osd_voSrc_e;

static osdVoObj_s gOsdVoObj=
{
    .fdhandle = 0,
    .fbEn = 0,
    .osdBufInfo = NULL
};

typedef enum __sgks_osd_device
{
    OSD_ON_UNKOWN  = 0,
    OSD_ON_CVBS,
    OSD_ON_STREAM,
} sgks_osd_device_e;

typedef struct __sgks_osd_overlay_insert_area_s
{
    //extended type OSD insert
    u16 enable;
    u16 width;
    u16 pitch;
    u16 height;
    u32 total_size;
    u16 start_x;
    u16 start_y;
    u32 clut_id;
    u8  *data;    //overlay data buffer (without CLUT)
} sgks_osd_overlay_insert_area_s;

typedef struct __sgks_osd_overlay_insert_s
{
#define MAX_NUM_OVERLAY_AREA    (3)
    u32   id;
    u32   enable;
    sgks_osd_overlay_insert_area_s    area[MAX_NUM_OVERLAY_AREA];
} sgks_osd_overlay_insert_s;

typedef struct __sgks_osd_enc_handle_s
{
    u32  hMDI;  /*MDI driver handle*/
    sgks_mpi_mem_s  overlay_mem_info;
    sgks_osd_device_e  device;  /*device of osd to display.*/
    sgks_osd_overlay_insert_s  osdPlane[OSD_PLANE_NUM];  /*each stream has one osd plane,and each osd plane has 3(OSD_AREA_NUM) area.*/
    sgks_mpi_osd_enc_area_mapping_s  areaMap[OSD_AREA_TOTAL_NUM];  /*each osd plane has 3(OSD_AREA_NUM) area.*/
} sgks_osd_enc_handle_s;

static sgks_osd_overlay_insert_s g_overlay_insert[MULTI_STREAM_MAX_NUM] =
{
    {
        .id = MEDIA_MAIN_STREAM,
        .enable = 0,
    },
    {
        .id = MEDIA_2ND_STREAM,
        .enable = 0,
    },
    {
        .id = MEDIA_3RD_STREAM,
        .enable = 0,
    },
    {
        .id = MEDIA_4TH_STREAM,
        .enable = 0,
    },
};
static sgks_osd_enc_handle_s *pOsdEncHandle;
static u16 OSD_PLANE_NUM_CONFIG     = OSD_PLANE_NUM;
static u16 OSD_AREA_NUM_CONFIG       = OSD_AREA_NUM;/*the number of areas of one plane.*/
static u16 OSD_AREA_TOTAL_NUM_CONFIG = OSD_AREA_TOTAL_NUM;

static int osd_DspCmdSend(char *dspCmd, int dspCmdSize)
{
    msg_t ioctlMsg;

    if(dspCmd == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }

    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_SENDCMD;
    ioctlMsg.msg_head.msg_size = dspCmdSize;
    memcpy(ioctlMsg.msg_data, dspCmd, dspCmdSize);
    if(ioctl(gOsdVoObj.fdhandle, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("ioctl msg send err.\n"));
        return SGKS_ERR_SYS_MALLOCERR;
    }
    return SGKS_SUCCESS;
}

static int osd_Mallc(sgks_mpi_mem_s *meminfo, u32 size)
{
    msg_t ioctlMsg;

    if(meminfo == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }
    meminfo->size = size;

    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_MALLOC;
    ioctlMsg.msg_head.msg_size = sizeof(sgks_mdi_mem_s);
    memcpy(ioctlMsg.msg_data, meminfo, sizeof(sgks_mdi_mem_s));
    if(ioctl(gOsdVoObj.fdhandle, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("ioctl msg send err.\n"));
        return SGKS_ERR_SYS_MALLOCERR;
    }
    memcpy(meminfo, ioctlMsg.msg_data, sizeof(sgks_mdi_mem_s));
    return SGKS_SUCCESS;
}

static int osd_Free(sgks_mpi_mem_s *meminfo)
{
    msg_t ioctlMsg;

    if(meminfo == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }

    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_FREE;
    ioctlMsg.msg_head.msg_size = sizeof(sgks_mdi_mem_s);
    memcpy(ioctlMsg.msg_data, meminfo, sizeof(sgks_mdi_mem_s));
    if(ioctl(gOsdVoObj.fdhandle, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("ioctl msg send err.\n"));
        return SGKS_ERR_SYS_FREEERR;
    }

    return SGKS_SUCCESS;
}

static int osd_CleanCache(sgks_mpi_mem_s *meminfo)
{
    msg_t ioctlMsg;
    sgks_mdi_opt_d_cache_s cache;

    if(meminfo == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }
    cache.cache_type = SGKS_OPT_D_CACHE_CLAEN;
    cache.start = meminfo->user_addr;
    cache.size = meminfo->size;
    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_OPT_D_CACHE;
    ioctlMsg.msg_head.msg_size = sizeof(sgks_mdi_opt_d_cache_s);
    memcpy(ioctlMsg.msg_data, &cache, sizeof(sgks_mdi_opt_d_cache_s));
    if(ioctl(gOsdVoObj.fdhandle, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("ioctl msg send err.\n"));
        return SGKS_ERR_SYS_FREEERR;
    }

    return SGKS_SUCCESS;
}

static int osd_BindFb(sgks_mdi_osdVoInfoToFb_s *info)
{
    msg_t ioctlMsg;

    if(info == NULL)
    {
        Printf("Error: parameter null\n");
        return SGKS_ERR_SYS_PARAMERR;
    }

    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_OSD_BIND_FB;
    ioctlMsg.msg_head.msg_size = sizeof(sgks_mdi_opt_d_cache_s);
    memcpy(ioctlMsg.msg_data, info, sizeof(sgks_mdi_opt_d_cache_s));
    if(ioctl(gOsdVoObj.fdhandle, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        Printf("ioctl msg send err.\n");
        return SGKS_ERR_SYS_FREEERR;
    }

    return SGKS_SUCCESS;
}

int sgks_mpi_Osd_Mallc(sgks_mpi_mem_s *meminfo, u32 size)
{
    int ret;
    ret = osd_Mallc(meminfo, size);
    return ret;
}

int sgks_mpi_Osd_Free(sgks_mpi_mem_s *meminfo)
{
    int ret;
    ret = osd_Free(meminfo);
    return ret;
}

int sgks_mpi_Osd_Open(int fbEn)
{
    int fd;
    if(gOsdVoObj.fdhandle)
    {
        return SGKS_SUCCESS;
    }

    if((fd = open(MPI_DRIVER_MEDIA_DEV, O_RDWR, 0)) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("err open mpi driver dev:%s\n", MPI_DRIVER_MEDIA_DEV));
        return SGKS_ERR_SYS_OPENDRIVERDEVERR;
    }
    gOsdVoObj.fbEn = fbEn;
    gOsdVoObj.fdhandle = fd;
    return SGKS_SUCCESS;
}

int sgks_mpi_Osd_VoParamSet(sgks_mpi_osd_voParamSetup_s *param)
{
    sgks_mpi_mem_s meminfo;
    sgks_dsp_cmd_vo_osd_setup_s osdSetup;

    if(gOsdVoObj.fdhandle == 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Erorr: osd not open\n"));
        return SGKS_FAIL;
    }

    if(param == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }

    memset(&osdSetup, 0, sizeof(osdSetup));
    osdSetup.cmd_code                 = SGKS_DSP_CMD_VO_OSD_SETUP;
    osdSetup.vo_id                    = param->vo_id;
    osdSetup.en                       = param->en;
    osdSetup.src                      = param->src;
    osdSetup.flip                     = param->flip;
    osdSetup.rescaler_en              = param->rescalerEn;
    osdSetup.premultiplied            = 0;
    osdSetup.global_blend             = 0xFF;
    osdSetup.win_offset_x             = param->winOffsetX;
    osdSetup.win_offset_y             = param->winOffsetY;
    osdSetup.win_width                = param->winWidth;
    osdSetup.win_height               = param->winHeight;
    osdSetup.rescaler_input_width     = param->rescalerInputWidth;
    osdSetup.rescaler_input_height    = param->rescalerInputHeight;
    osdSetup.osd_buf_dram_addr        = 0;
    osdSetup.osd_buf_pitch            = param->winWidth<<1;
    osdSetup.osd_buf_repeat_field     = 0;
    osdSetup.osd_direct_mode          = param->directMode;
    osdSetup.osd_transparent_color    = 0;
    osdSetup.osd_transparent_color_en = 1;
    osdSetup.reserved                 = 0;

    osd_Mallc(&meminfo, sizeof(sgks_dram_osd_s));
    memset(meminfo.user_addr, 0, meminfo.size);
    osdSetup.osd_buf_info_dram_addr   = (u32)meminfo.phy_addr;

    if (osd_DspCmdSend((char *)&osdSetup, sizeof(sgks_dsp_cmd_vo_osd_setup_s)) != SGKS_SUCCESS)
    {
        return SGKS_ERR_SYS_FWCMDSENDERR;
    }
    gOsdVoObj.osdBufInfo = (sgks_dram_osd_s *)meminfo.user_addr;
    gOsdVoObj.osdBufInfo->osd_buf_pitch = param->winWidth*2;
    osd_CleanCache(&meminfo);
    if(gOsdVoObj.fbEn)
    {
        sgks_mdi_osdVoInfoToFb_s info;
        info.width = osdSetup.win_width;
        info.height = osdSetup.win_height;
        info.osd_buf_info_phy_addr = osdSetup.osd_buf_info_dram_addr;
        info.directMode = osdSetup.osd2_direct_mode;
        osd_BindFb(&info);
    }
    return SGKS_SUCCESS;
}

int sgks_mpi_Osd_VoUpdateDisplay(sgks_mpi_mem_s *meminfo)
{
    if(gOsdVoObj.fdhandle == 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Erorr: osd not open\n"));
        return SGKS_FAIL;
    }

    if(meminfo == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: parameter null\n"));
        return SGKS_ERR_SYS_PARAMERR;
    }

    osd_CleanCache(meminfo);

    gOsdVoObj.osdBufInfo->osd_buf_dram_addr = (u32)meminfo->phy_addr;
    return SGKS_SUCCESS;
}


static int sgks_osd_check_area_params(sgks_mpi_osd_enc_area_params_s *areaParams)
{
    u32 pitch, areaSize;
    u8  areaIndex;

    if((areaParams->planeId >= OSD_PLANE_NUM_CONFIG) || (areaParams->areaId >= OSD_AREA_NUM_CONFIG))
    {
        DEBUGMSG(ZONE_ERROR, ("invalid planeId=%d or areaId=%d.\n", areaParams->planeId, areaParams->areaId));
        return SGKS_ERR_OSD_PARAMERR;
    }

    if((areaParams->enable) && ((!areaParams->width) || (!areaParams->height)))
    {
        DEBUGMSG(ZONE_ERROR, ("invalid area size %dx%d.\n", areaParams->width, areaParams->height));
        return SGKS_ERR_OSD_PARAMERR;
    }

    areaIndex = areaParams->planeId * OSD_AREA_NUM_CONFIG + areaParams->areaId;

    if(areaParams->enable)
    {
        pitch = ROUND_UP(areaParams->width, 16);
        areaParams->height = ROUND_UP(areaParams->height, 4); // overlay area height must be multiple of 4
        areaSize = areaParams->height * pitch;

        if(areaSize > pOsdEncHandle->areaMap[areaIndex].areaSize)
        {
            DEBUGMSG(ZONE_ERROR, ("osd area size [%d] is larger than pre-allocated memory [%d].\n",
                                  areaSize, pOsdEncHandle->areaMap[areaIndex].areaSize));
            return SGKS_ERR_OSD_PARAMERR;
        }
    }

    return SGKS_SUCCESS;
}

static int sgks_osd_check_overlay_insert_area(sgks_osd_overlay_insert_s *info, int stream)
{
    int ret = SGKS_SUCCESS;
    int i, width, height;
    sgks_osd_overlay_insert_area_s *area;
    sgks_mpi_venc_stream_format_param_s    VencStreamFormatParam;
    memset(&VencStreamFormatParam, 0x00, sizeof(VencStreamFormatParam));
    VencStreamFormatParam.streamId = stream;

    ret = sgks_mpi_venc_get_params(VENC_PARAM_TYPE_STREAM, (void *)&VencStreamFormatParam);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Get venc sream format param fail!%s\n", __FUNCTION__));
        return ret;
    }
    width = VencStreamFormatParam.width;
    height = VencStreamFormatParam.height;
    for(i = 0; i < OVERLAY_AREA_NUM; ++i)
    {
        area = &info->area[i];

        if(area->enable)
        {
            if(area->clut_id >= OVERLAY_CLUT_NUM)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area clut id [%d] must be not larger than 15.\n", area->clut_id));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(!area->pitch || !area->width || !area->height)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area pitch/width/height cannot be zero.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->pitch < area->width)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area pitch must be not smaller than width.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->start_x & 0x1)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area start x must be multiple of 2.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->start_y & 0x3)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area start y must be multiple of 4.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->width & 0x1)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area width must be multiple of 2.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->height & 0x3)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area height must be multiple of 4.\n"));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if(area->width > OVERLAY_AREA_MAX_WIDTH)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area width [%d] must be no greater than %d.\n", area->width, OVERLAY_AREA_MAX_WIDTH));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if((area->start_x + area->width) > width)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area width [%d] with offset [%d] is out of stream width [%d].\n", area->width, area->start_x, width));
                return SGKS_ERR_OSD_PARAMERR;
            }

            if((area->start_y + area->height) > height)
            {
                DEBUGMSG(ZONE_ERROR, ("overlay area height [%d] with offset [%d] is out of stream height [%d].\n", area->height, area->start_y, height));
                return SGKS_ERR_OSD_PARAMERR;
            }
        }
    }

    return ret;
}

static int sgks_osd_cmd_osd_insert(sgks_osd_overlay_insert_s *info, int stream)
{
    int ret = SGKS_SUCCESS;
    sgks_dsp_cmd_ipcam_osd_insert_s dsp_cmd;
    sgks_osd_overlay_insert_area_s area;
    int i, active_areas;
    u32 addr_phy;

    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_IPCAM_OSD_INSERT, stream);
    if(info->enable != 0)
    {
        dsp_cmd.vo_id = 1;//use voutB osd module
        dsp_cmd.osd_enable = 1;
        for(i = 0, active_areas = 0; i < 3; ++i)
        {
            area = info->area[i];
            if(area.enable)
            {
                //dump user data for debugging
                if(pOsdEncHandle->overlay_mem_info.phy_addr == NULL)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s overlay have not malloc.\n", __FUNCTION__));
                    return SGKS_ERR_OSD_PARAMERR;
                }
                addr_phy = (u32)(pOsdEncHandle->overlay_mem_info.phy_addr) + area.clut_id * OVERLAY_CLUT_SIZE;
                dsp_cmd.osd_clut_dram_address[active_areas] = addr_phy;
                //DEBUGMSG(ZONE_INFO, ("overlay area %d clut address 0x%08X, clut id %d, data addr 0x%08X.\n",  i, dsp_cmd.osd_clut_dram_address[i], area.clut_id, (u32)area.data));
                addr_phy = area.data - (u32)(pOsdEncHandle->overlay_mem_info.user_addr) +  (u32)(pOsdEncHandle->overlay_mem_info.phy_addr);
                dsp_cmd.osd_buf_dram_address[active_areas] =  addr_phy;
                dsp_cmd.osd_buf_pitch[active_areas] = area.pitch;
                dsp_cmd.osd_win_offset_x[active_areas] = area.start_x;
                dsp_cmd.osd_win_offset_y[active_areas] = area.start_y;
                dsp_cmd.osd_win_w[active_areas] = area.width;
                dsp_cmd.osd_win_h[active_areas] = area.height;
                ++active_areas;
                //clean cache on buf data
                {
                    u8 *msg_buf = NULL;
                    SGKS_MDI_DRV_BUFF(msg_buf);
                    sgks_mdi_opt_d_cache_s *cache = msg_buf;
                    cache->cache_type  = SGKS_OPT_D_CACHE_CLAEN;
                    addr_phy = area.data - (u32)(pOsdEncHandle->overlay_mem_info.user_addr) +  (u32)(pOsdEncHandle->overlay_mem_info.phy_addr);
                    cache->start  = addr_phy;
                    cache->size   = area.pitch * area.height;
                    SGKS_MDI_DRV_IOCTL_EX(pOsdEncHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
                }
                {
                    u8 *msg_buf = NULL;
                    SGKS_MDI_DRV_BUFF(msg_buf);
                    sgks_mdi_opt_d_cache_s *cache = msg_buf;
                    cache->cache_type  = SGKS_OPT_D_CACHE_CLAEN;
                    addr_phy = (u32)(pOsdEncHandle->overlay_mem_info.phy_addr) + area.clut_id * OVERLAY_CLUT_SIZE;
                    cache->start  = addr_phy;
                    cache->size   = OVERLAY_CLUT_SIZE;
                    SGKS_MDI_DRV_IOCTL_EX(pOsdEncHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
                }
            }
        }
        dsp_cmd.osd_num_regions = active_areas;
    }

    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, vo_id);
    mpi_cmd(dsp_cmd, osd_enable);
    mpi_cmd(dsp_cmd, osd_num_regions);
    mpi_cmd_hex(dsp_cmd, osd_clut_dram_address[0]);
    mpi_cmd_hex(dsp_cmd, osd_buf_dram_address[0]);
    mpi_cmd(dsp_cmd, osd_buf_pitch[0]);
    mpi_cmd(dsp_cmd, osd_win_offset_x[0]);
    mpi_cmd(dsp_cmd, osd_win_offset_y[0]);
    mpi_cmd(dsp_cmd, osd_win_w[0]);
    mpi_cmd(dsp_cmd, osd_win_h[0]);
    mpi_cmd_hex(dsp_cmd, osd_clut_dram_address[1]);
    mpi_cmd_hex(dsp_cmd, osd_buf_dram_address[1]);
    mpi_cmd(dsp_cmd, osd_buf_pitch[1]);
    mpi_cmd(dsp_cmd, osd_win_offset_x[1]);
    mpi_cmd(dsp_cmd, osd_win_offset_y[1]);
    mpi_cmd(dsp_cmd, osd_win_w[1]);
    mpi_cmd(dsp_cmd, osd_win_h[1]);
    mpi_cmd_hex(dsp_cmd, osd_clut_dram_address[2]);
    mpi_cmd_hex(dsp_cmd, osd_buf_dram_address[2]);
    mpi_cmd(dsp_cmd, osd_buf_pitch[2]);
    mpi_cmd(dsp_cmd, osd_win_offset_x[2]);
    mpi_cmd(dsp_cmd, osd_win_offset_y[2]);
    mpi_cmd(dsp_cmd, osd_win_w[2]);
    mpi_cmd(dsp_cmd, osd_win_h[2]);
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: Send command 0x%x fail\n", __FUNCTION__, dsp_cmd.cmd_code));
    }

    return ret;
}

static int sgks_osd_overlay_insert(sgks_osd_overlay_insert_s  *pOsdOverlayInsert)
{
    int ret = SGKS_SUCCESS;
    sgks_osd_overlay_insert_s info;
    int retv;
    int stream = -1;

    //copy from user
    memcpy(&info, pOsdOverlayInsert, sizeof(info));

    //check user space addr mapping.
    if(pOsdEncHandle->overlay_mem_info.user_addr == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("overlay/alphamask not mapped\n"));
        return SGKS_ERR_OSD_PARAMERR;
    }

    stream = info.id;
    if(info.enable != 0)
    {
        if(SGKS_SUCCESS != venc_check_encode_format_limit(info.id))
        {
            DEBUGMSG(ZONE_ERROR, ("Please set encode format before overlay configuration.\n"));
            return SGKS_ERR_OSD_PARAMERR;
        }
#if 0 //Delete by liuzejian 20180329
        //check overlay insert area
        if(SGKS_SUCCESS != sgks_osd_check_overlay_insert_area(&info, stream))
        {
            DEBUGMSG(ZONE_ERROR,("overlay insert area format error\n"));
            return SGKS_ERR_OSD_PARAMERR;
        }
#endif
        if(SGKS_SUCCESS != venc_cmd_encode_size_setup(stream))
        {
            DEBUGMSG(ZONE_ERROR, ("Failed to set encode format ex.\n"));
            return SGKS_ERR_OSD_PARAMERR;
        }
    }

    ret = sgks_osd_cmd_osd_insert(&info, stream);
    if(SGKS_SUCCESS != ret)
    {
        DEBUGMSG(ZONE_ERROR, ("set overlay insert failed.\n"));
        return ret;
    }

    memcpy(&g_overlay_insert[stream], &info, sizeof(sgks_osd_overlay_insert_s));
    return ret;

}

static int sgks_osd_get_overlay_insert( sgks_osd_overlay_insert_s  *pOsdOverlayInsert)
{
    if(pOsdOverlayInsert == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("%s param is null\n", __FUNCTION__));
        return SGKS_ERR_OSD_PARAMERR;
    }
    memcpy(pOsdOverlayInsert, &g_overlay_insert[pOsdOverlayInsert->id], sizeof(sgks_osd_overlay_insert_s));
    return SGKS_SUCCESS;
}


int sgks_mpi_osd_enc_init(void)
{
    int ret = SGKS_SUCCESS;
    sgks_mpi_manager_s *mpi =NULL;

    pOsdEncHandle = (sgks_osd_enc_handle_s *)sgks_mpi_Malloc(sizeof(sgks_osd_enc_handle_s));
    if(pOsdEncHandle == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: Out of memory %s\n", __FUNCTION__));
        return SGKS_ERR_OSD_MALLOCERR;
    }
    memset(pOsdEncHandle, 0x00, sizeof(sgks_osd_enc_handle_s));

    ret = sgks_mpi_Osd_Open(1);
    if(ret != SGKS_SUCCESS)
    {
        return SGKS_ERR_OSD_DEVICEERR;
    }
    pOsdEncHandle->hMDI = gOsdVoObj.fdhandle;

    return ret;
}

int sgks_mpi_osd_enc_deinit(void)
{
    if(pOsdEncHandle != NULL)
    {
        sgks_mpi_Free(pOsdEncHandle);
    }
    pOsdEncHandle = NULL;
    return SGKS_SUCCESS;
}

int sgks_mpi_osd_enc_config_area_mem(sgks_osd_enc_area_mem_param_s *areamem)
{
    int ret = SGKS_SUCCESS;
    u32 cnt;
    u32 areasize, osdyuvoffset;

    if((areamem == NULL) || (areamem->planeNum == 0) || (areamem->areaNum == 0))
    {
        return SGKS_ERR_OSD_PARAMERR;
    }
    switch(areamem->areaNum)
    {
        case 1:
        {
            areasize = areamem->planeNum * areamem->areaNum * areamem->areaSize[0];
            break;
        }
        case 2:
        {
            areasize = areamem->planeNum * (areamem->areaSize[0] + areamem->areaSize[1]);
            break;
        }
        case 3:
        {
            areasize = areamem->planeNum * (areamem->areaSize[0] + areamem->areaSize[1] + areamem->areaSize[2]);
            break;
        }
        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: %s areaNum:%d\n", __FUNCTION__, areamem->areaNum));
            break;
        }
    }

    areasize += areamem->planeNum * areamem->areaNum * OSD_CLUT_SIZE;
    sgks_mpi_mem_s meminfo;
    meminfo.size = areasize;

    msg_t ioctlMsg;
    memset(&ioctlMsg, 0, sizeof(ioctlMsg));
    ioctlMsg.msg_head.msg_type = SGKS_MDI_OPERATION_MALLOC;
    ioctlMsg.msg_head.msg_size = sizeof(sgks_mdi_mem_s);
    memcpy(ioctlMsg.msg_data, &meminfo, sizeof(sgks_mdi_mem_s));
    if(ioctl(pOsdEncHandle->hMDI, SGKS_MDI_IOCTL_OPERATION, &ioctlMsg) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: Out of memory %s\n", __FUNCTION__));
        return SGKS_ERR_SYS_MALLOCERR;
    }
    memcpy(&meminfo, ioctlMsg.msg_data, sizeof(sgks_mdi_mem_s));
    memcpy(&pOsdEncHandle->overlay_mem_info, &meminfo, sizeof(sgks_mpi_mem_s));
    memset(meminfo.user_addr, 0, meminfo.size);
    OSD_PLANE_NUM_CONFIG = areamem->planeNum;
    OSD_AREA_NUM_CONFIG = areamem->areaNum;
    OSD_AREA_TOTAL_NUM_CONFIG = OSD_PLANE_NUM_CONFIG * OSD_AREA_NUM_CONFIG;
    osdyuvoffset = OSD_AREA_TOTAL_NUM_CONFIG * OSD_CLUT_SIZE;

    for(cnt = 0; cnt < OSD_AREA_TOTAL_NUM_CONFIG; cnt++)
    {
        pOsdEncHandle->areaMap[cnt].areaId        = cnt;
        pOsdEncHandle->areaMap[cnt].clutSize      = OSD_CLUT_SIZE;
        pOsdEncHandle->areaMap[cnt].clutStartAddr = meminfo.user_addr + (OSD_CLUT_SIZE * cnt);
        pOsdEncHandle->areaMap[cnt].areaSize      = areamem->areaSize[cnt/OSD_AREA_NUM_CONFIG];
        pOsdEncHandle->areaMap[cnt].areaStartAddr = meminfo.user_addr + osdyuvoffset;
        osdyuvoffset += areamem->areaSize[cnt];
    }

    DEBUGMSG(ZONE_INFO, ("osd remap: start = %p, total size = 0x%x,planeNum:%u, areaNum:%u\n",
                         meminfo.user_addr, meminfo.size, areamem->planeNum, areamem->areaNum));

    return ret;
}


int sgks_mpi_osd_enc_get_area_mapping(sgks_mpi_osd_enc_area_index_s areaIndex, sgks_mpi_osd_enc_area_mapping_s *areaMapping)
{
    int ret = SGKS_SUCCESS;
    if(areaMapping == NULL)
    {
        return SGKS_ERR_OSD_PARAMERR;
    }

    if((areaIndex.planeId >= OSD_PLANE_NUM_CONFIG) || (areaIndex.areaId >= OSD_AREA_NUM_CONFIG))
    {
        return SGKS_ERR_OSD_PARAMERR;
    }

    memcpy(areaMapping,
           &(pOsdEncHandle->areaMap[areaIndex.planeId*OSD_AREA_NUM_CONFIG + areaIndex.areaId]),
           sizeof(sgks_mpi_osd_enc_area_mapping_s));

    return ret;
}


int sgks_mpi_osd_enc_set_area_params(sgks_mpi_osd_enc_area_params_s *areaParams)
{
    int ret =SGKS_SUCCESS;
    if(areaParams == NULL)
    {
        return SGKS_ERR_OSD_PARAMERR;
    }

    ret= sgks_osd_check_area_params(areaParams);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: osd params error\n", __FUNCTION__));
        return ret;
    }

    sgks_mpi_dsp_status_s   dsp_state;

    dsp_state.op_mode = SGKS_DSP_UNKNOWN_MODE;
    dsp_state.op_sub_mode = SGKS_DSP_ENC_UNKNOWN_MODE;
    dsp_state.state = SGKS_ENC_UNKNOWN_STATE;

    ret = sgks_mpi_sys_GetDspStats(&dsp_state);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s:Get DSP STATE FAIL\n", __FUNCTION__));
        return SGKS_ERR_VENC_DEVICEERR;
    }

    if((dsp_state.op_mode != SGKS_DSP_ENCODE_MODE) || (dsp_state.state != SGKS_ENC_BUSY_STATE))
    {
        DEBUGMSG(ZONE_ERROR, ("%s: error:dsp is not encoding!\n", __FUNCTION__));
        return SGKS_ERR_VENC_STATEERROR;
    }

    u16 pitch;
    u8  areaIndex;

    sgks_osd_overlay_insert_area_s *targetArea  = NULL;
    sgks_osd_overlay_insert_s      *targetPlane = NULL;
    targetPlane = &(pOsdEncHandle->osdPlane[areaParams->planeId]);
    targetArea  = &(pOsdEncHandle->osdPlane[areaParams->planeId].area[areaParams->areaId]);
    pitch       = ROUND_UP(areaParams->width, 16);
    areaIndex   = areaParams->planeId * OSD_AREA_NUM_CONFIG + areaParams->areaId;

    if(areaParams->enable)
    {
        targetArea->width  = areaParams->width;
        targetArea->height = ROUND_UP(areaParams->height, 4);
        targetArea->pitch  = pitch;
        targetArea->total_size = areaParams->height * pitch;
        targetArea->start_x    = areaParams->offsetX;
        targetArea->start_y    = areaParams->offsetY;
        targetArea->clut_id    = areaIndex;
        targetArea->data       = pOsdEncHandle->areaMap[areaIndex].areaStartAddr;
    }

    targetArea->enable  = areaParams->enable;
    targetPlane->id     = areaParams->planeId;
    targetPlane->enable = targetPlane->area[0].enable |
                          targetPlane->area[1].enable |
                          targetPlane->area[2].enable;

    ret = sgks_osd_overlay_insert(targetPlane);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR,("osd overlay insert return error\n"));
    }
    return ret;
}

int sgks_mpi_osd_enc_get_area_params(sgks_mpi_osd_enc_area_params_s  *areaParams)
{
    int ret = SGKS_SUCCESS;
    sgks_osd_overlay_insert_area_s *targetArea  = NULL;
    sgks_osd_overlay_insert_s      *targetPlane = NULL;

    if(areaParams == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("%s params is null\n", __FUNCTION__));
        return SGKS_ERR_OSD_PARAMERR;
    }

    /*check input plane index & area index.*/
    if((areaParams->planeId >= OSD_PLANE_NUM_CONFIG) || (areaParams->areaId >= OSD_AREA_NUM_CONFIG))
    {
        DEBUGMSG(ZONE_ERROR, ("invalid planeId=%d or areaId=%d.\n", areaParams->planeId, areaParams->areaId));
        return SGKS_ERR_OSD_PARAMERR;
    }

    {
        sgks_mpi_dsp_status_s   dsp_state;
        dsp_state.op_mode = SGKS_DSP_UNKNOWN_MODE;
        dsp_state.op_sub_mode = SGKS_DSP_ENC_UNKNOWN_MODE;
        dsp_state.state = SGKS_ENC_UNKNOWN_STATE;

        ret = sgks_mpi_sys_GetDspStats(&dsp_state);
        if(ret != SGKS_SUCCESS)
        {
            DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
            return SGKS_ERR_VENC_DEVICEERR;
        }

        if((dsp_state.op_mode != SGKS_DSP_ENCODE_MODE) || (dsp_state.state != SGKS_ENC_BUSY_STATE))
        {
            return SGKS_ERR_VENC_STATEERROR;
        }
    }

    targetPlane = &(pOsdEncHandle->osdPlane[areaParams->planeId]);
    targetArea  = &(pOsdEncHandle->osdPlane[areaParams->planeId].area[areaParams->areaId]);

    ret = sgks_osd_get_overlay_insert(targetPlane);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("get overlay info failed.\n"));
        return ret;
    }
    areaParams->enable = targetPlane->enable;
    areaParams->width  = targetArea->width;
    areaParams->height = targetArea->height;
    areaParams->offsetX = targetArea->start_x;
    areaParams->offsetY = targetArea->start_y;
    return ret;
}


